package com.pt25.base.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.compressors.deflate.DeflateCompressorInputStream;
import org.apache.commons.compress.compressors.deflate.DeflateCompressorOutputStream;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;

@Slf4j
public class InflaterUtil {


    private static byte[] compressByte(byte[] data) {
        return compressByte(data, 4096);
    }

    private static byte[] compressByte(byte[] data, int size) {
        try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
             ByteArrayOutputStream bos = new ByteArrayOutputStream();
             DeflateCompressorOutputStream dcos = new DeflateCompressorOutputStream(bos)) {
            byte[] buffer = new byte[size];
            int len;
            // 防止死循环, 如果 input 数据损坏，inflater.finished() 可能永远不返回 true，导致 死循环
            // 要注意这里的 500 会限制压缩数据的大小，maxAttempts 太小了会导致数据丢失！！！！！！！！！
            int maxAttempts = 500;
            while ((len = bis.read(buffer)) != -1 && maxAttempts-- > 0) {
                dcos.write(buffer, 0, len);
            }
            if (maxAttempts <= 0) {
                throw new IllegalStateException("压缩失败，可能数据损坏!");
            }
            dcos.finish(); // finish compression
            return bos.toByteArray();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return new byte[]{};
    }

    private static byte[] uncompressByte(byte[] data) {
        return uncompressByte(data, 4096);
    }


    private static byte[] uncompressByte(byte[] data, int size) {
        try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
             ByteArrayOutputStream bos = new ByteArrayOutputStream();
             DeflateCompressorInputStream dcis = new DeflateCompressorInputStream(bis)) {
            byte[] buffer = new byte[size];
            int len;
            // 防止死循环, 如果 input 数据损坏，inflater.finished() 可能永远不返回 true，导致 死循环
            // 要注意这里的 500 会限制压缩数据的大小，maxAttempts 太小了会导致数据丢失！！！！！！！！！
            int maxAttempts = 500;
            while ((len = dcis.read(buffer)) != -1 && maxAttempts-- > 0) {
                bos.write(buffer, 0, len);
            }
            if (maxAttempts <= 0) {
                throw new IllegalStateException("解压失败，可能数据损坏!");
            }
            return bos.toByteArray();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return new byte[]{};
    }

    public static String compress(Object data) {
        byte[] compressData = compressByte((JsonUtil.toJson(data)).getBytes());
        return Base64.getEncoder().encodeToString(compressData);
    }

    public static String compress(Object data, int size) {
        byte[] compressData = compressByte((JsonUtil.toJson(data)).getBytes(), size);
        return Base64.getEncoder().encodeToString(compressData);
    }

    public static String uncompress(Object data) {
        String base64Data = (String) data;
        byte[] compressData = Base64.getDecoder().decode(base64Data);
        return new String(uncompressByte(compressData));
    }

    public static String uncompress(Object data, int size) {
        String base64Data = (String) data;
        byte[] compressData = Base64.getDecoder().decode(base64Data);
        return new String(uncompressByte(compressData, size));
    }
}
